package com.jueling.culture.compent;


import com.jueling.culture.util.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author linp
 * @date 2022/04/09
 */


@Component
public class RedisComponent {

    @Autowired
    private RedisTemplate redisTemplate;

    private static final String REDIS_LUA_SCRIPT = " local r =0 ;  local k= redis.call('incr',KEYS[1]); if(k>5) then return r; end; if(k==1) then redis.call('expire',KEYS[1],60) ; end;  local n=redis.call('set',KEYS[2],1,'EX',60,'NX');if(n) then   return r+1 ;   end return r; ";

    /**
     * 带有过期时间的setnx
     * @param key
     * @param value
     * @param expireTime
     * @return
     */
    public boolean setNxExpire(String key,String value,long expireTime) {
        return this.set(key, value, "NX", "EX", expireTime);

    }

    /**
     * set
     * @param key
     * @param value
     * @param nxxx
     * @param expx
     * @param time
     * @return
     */
    public boolean set(final String key, final String value, final String nxxx, final String expx, final long time) {
        Object result = redisTemplate.execute(new RedisCallback<Object>() {

            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
                Object set = connection.execute("set", new byte[][]{
                        serializer.serialize(key), serializer.serialize(value),
                        serializer.serialize(nxxx), serializer.serialize(expx),
                        serializer.serialize(String.valueOf(time))

                });


                return set!=null;
            }
        });


        return (Boolean) result;
    }

    /**
     * 泛型
     * @param key
     * @param value
     * @return
     */
    public boolean setObj(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            operations.set(key, JsonUtil.object2JsonString(value));
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 泛型
     * @param key
     * @param value
     * @param expireTime
     * @return
     */
    public boolean setObj(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            operations.set(key, JsonUtil.object2JsonString(value));
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 泛型
     * @param key
     * @param valueType
     * @param <T>
     * @return
     */
    public <T> T getObj(final String key, Class<T> valueType) {
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        Object result = operations.get(key);
        if (result == null) {
            return null;
        }
        return JsonUtil.jsonString2Object(result.toString(),valueType);
    }

    /**
     * 写入缓存
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 写入缓存设置时效时间
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 批量删除对应的value
     * @param keys
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 批量删除key
     * @param pattern
     */
    public void removePattern(final String pattern) {
        Set<String> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0){
            redisTemplate.delete(keys);
        }
    }
    /**
     * 删除对应的value
     * @param key
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }
    /**
     * 判断缓存中是否有对应的value
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }
    /**
     * 读取缓存
     * @param key
     * @return
     */
    public Object get(final String key) {
        Object result = null;
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }
    /**
     * 哈希 添加
     * @param key
     * @param hashKey
     * @param value
     */
    public void hmSet(String key, Object hashKey, Object value){
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        hash.put(key,hashKey,value);
    }

    /**
     * 哈希获取数据
     * @param key
     * @param hashKey
     * @return
     */
    public Object hmGet(String key, Object hashKey){
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        return hash.get(key,hashKey);
    }

    /**
     * 列表添加
     * @param k
     * @param v
     */
    public void lPush(String k,Object v){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.rightPush(k,v);
    }

    /**
     * 列表获取
     * @param k
     * @param l
     * @param l1
     * @return
     */
    public List<Object> lRange(String k, long l, long l1){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        return list.range(k,l,l1);
    }

    /**
     * 集合添加
     * @param key
     * @param value
     */
    public void add(String key,Object value){
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        set.add(key,value);
    }

    /**
     * 集合获取
     * @param key
     * @return
     */
    public Set<Object> setMembers(String key){
        SetOperations<String, Object> set = redisTemplate.opsForSet();
        return set.members(key);
    }

    /**
     * 有序集合添加
     * @param key
     * @param value
     * @param scoure
     */
    public void zAdd(String key,Object value,double scoure){
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        zset.add(key,value,scoure);
    }

    /**
     * 有序集合获取
     * @param key
     * @param scoure
     * @param scoure1
     * @return
     */
    public Set<Object> rangeByScore(String key,double scoure,double scoure1){
        ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
        return zset.rangeByScore(key, scoure, scoure1);
    }

    public Long increment(String key,Long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }
    public Long decrement(String key,Long delta) {
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    /**
     * 获取key失效生于时间
     * @param key
     * @return
     */
    public Long getKeyExpireTime(String key){
        return redisTemplate.getExpire(key,TimeUnit.SECONDS);
    }

    /**
     * 模糊查找key
     * @param key
     * @return
     */
    public Set<String> getKeys(String key){
        Set<String> keys = redisTemplate.keys(key);
        return keys;
    }

    public boolean setTimer(final String key, Object value, Long expireTime,TimeUnit milliseconds) {
        boolean result = false;
        try {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, milliseconds);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public boolean execute(String ipKey, String phoneKey) {
        List<String> keys = new ArrayList<>();
        keys.add(ipKey);
        keys.add(phoneKey);
        List<Object> argv = new ArrayList<>();
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(REDIS_LUA_SCRIPT, Long.class);
        Long execute = (Long) redisTemplate.execute(redisScript, keys, argv);
        return execute == 1;
    }

    /**
     * 根据key设置过期时间
     * @param key
     * @param expireTime
     * @return
     */
    public boolean extendExpirTime(String key, Long expireTime) {
        boolean result = false;
        try {
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

}